<?php

namespace App\Http\Requests\Account\Attendance;

use Carbon\Carbon;
use App\Models\User;
use Illuminate\Validation\Rule;
use App\Package\Attendance\Time;
use App\Exceptions\GeneralException;
use App\Models\System\Infrastructure;
use Illuminate\Foundation\Http\FormRequest;

/**
 * 用户打卡请求逻辑
 *
 * Date: 17/04/2018
 * @author George
 * @package App\Http\Requests\Account\Attendance
 */
class SigninRequest extends FormRequest
{
	/**
	 * 用户授权
	 *
	 * Date: 17/04/2018
	 * @author George
	 * @return bool
	 * @throws GeneralException
	 */
	public function authorize()
	{
		$now = Carbon::now();
		/**
		 * @var User $user
		 */
		$user = $this->user();
		$projects = $user->getProjects();

		// 判断是否加入公司
		if (!$user->hasCompany()) {
			throw new GeneralException('您没有加入公司，无法签到', 403);
		}

		// 判断用户是否拥有项目
		if ($projects->isEmpty()) {
			throw new GeneralException('您没有加入项目，无法签到', 403);
		}

		// 判断用户是否有排班
		if ($schedule = $user->getSchedule($this->get('type'))) {
			$this->offsetSet('schedule_id', $schedule->id);
		} else {
			throw new GeneralException('今天您没有排班，无法签到', 403);
		}

		//判断有没有设置允许提前签到时间
		if ($earlier = Infrastructure::query()->where('company_id', $schedule->company_id)->value('earlier')) {
			//当允许提前签到的时间大于当前时间就抛出异常
			if ((strtotime($schedule->start_timestamp) - $earlier * 60) - time() > 0) {
				throw new GeneralException('还没到允许签到的时间', 403);
			}
		}

		// 判断打卡类型
		if ($this->get('type') === 'checkin') {
			// 判断当天的排班是否已存在签到记录，如果有则抛出异常
			if ($schedule->attendance) {
				throw new GeneralException('您今天已经签到，无法再次签到', 403);
			}

			// 判断用户是否拥有指定项目
			if ($projects->contains($schedule->project_id)) {
				$attributes = [
					'user_id' => $user->id,
					'project_id' => $schedule->project_id,
					'company_id' => $user->company_id,
					'schedule_id' => $schedule->id,
					'genre_id' => $schedule->genre_id,
					'genre_name' => $schedule->genre_name,
					'checkin_time' => $now->toDateTimeString(),
					'checkin_longitude' => $this->get('longitude'),
					'checkin_latitude' => $this->get('latitude'),
					'checkin_address' => $this->get('address'),
					'checkin_example' => $this->get('example'),
					'checkin_image' => $this->get('selfie'),
					'time_difference' => strtotime($schedule->start_timestamp) - time(),
				];

				$addition = $this->get('addition');
				// 判断考勤是否外出或实习班，如果是则不计算考勤状态
				if ($addition) {
					$attributes['checkin_status'] = $addition;
				} else {
					$attributes['checkin_status'] = Time::check($schedule, $now->toDateTimeString(), $this->get('type'), $user->company_id);
				}

				// 替换掉用户输入的表单内容
				$this->replace($attributes);
			} else {
				throw new GeneralException('排班项目与所在项目不符', 403);
			}
		} else {
			$attendance = optional($schedule)->attendance;
			// 判断是否已经签到
			if (!$attendance) {
				throw new GeneralException('您还未签到，请先签到', 403);
			}

			$attributes = [
				'checkout_longitude' => $this->get('longitude'),
				'checkout_latitude' => $this->get('latitude'),
				'checkout_address' => $this->get('address'),
				'checkout_example' => $this->get('example'),
				'checkout_image' => $this->get('selfie'),
				'checkout_time' => $now->toDateTimeString(),
				'attendance' => $attendance
			];

			$addition = $this->get('addition');

			// 判断考勤是否外出或实习班，如果是则不计算考勤状态
			if ($addition) {
				$attributes['checkout_status'] = $addition;
			} else {
				$attributes['checkout_status'] = Time::check($schedule, $now->toDateTimeString(), $this->get('type'), $user->company_id);
			}

			// 替换掉用户输入的表单内容
			$this->replace($attributes);
		}
		// 移除Type 字段
		$this->offsetUnset('type');
		return true;
	}

	/**
	 * 定义表单验证规则
	 *
	 * Date: 17/04/2018
	 * @author George
	 * @return array
	 */
	public function rules()
	{
		return [
			'longitude' => ['required', 'regex:/^[\-\+]?(0?\d{1,2}\.\d{1,5}|1[0-7]?\d{1}\.\d{1,6}|180\.0{1,6})$/'],
			'latitude' => ['required', 'regex:/^[\-\+]?([0-8]?\d{1}\.\d{1,6}|90\.0{1,6})$/'],
			'address' => 'required',
			'example' => 'required',
			'selfie' => 'required',
			'type' => ['required', Rule::in(['checkin', 'checkout'])],
			'addition' => ['nullable', Rule::in(['legwork', 'practice'])]
		];
	}

	/**
	 * 定义错误消息
	 *
	 * Date: 16/04/2018
	 * @author George
	 * @return array
	 */
	public function messages()
	{
		return [
			'longitude.required' => '请提供签到的经度',
			'longitude.regex' => '签到的经度无效',
			'latitude.required' => '请提供签到的纬度',
			'latitude.regex' => '签到的纬度无效',
			'address.required' => '未获取到地址信息',
			'example.required' => '示例图片无效',
			'selfie.required' => '请选择签到的项目',
			'type.required' => '请选择打卡类型',
			'type.in' => '打卡类型错误',
			'addition.in' => '类型有误'
		];
	}
}
